package com.ithe.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ithe.core.constant.SmsKey;
import com.ithe.core.exception.BizException;
import com.ithe.core.utils.Md5Utils;
import com.ithe.user.mapper.UserMapper;
import com.ithe.user.pojo.dto.RegisterDto;
import com.ithe.user.pojo.dto.TokenDto;
import com.ithe.user.pojo.entity.User;
import com.ithe.user.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Calendar;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @BelongsProject: housekeeping
 * @BelongsPackage: com.ithe.user.service.impl
 * @Author: jingjianghao
 * @CreateTime: 2022-08-30  19:58
 * @Description: TODO
 * @Version: 1.0
 */
@RequiredArgsConstructor
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private final RedisTemplate redisTemplate;

    private final UserMapper userMapper;
    //private final UserService userService;
    @Override
    public void register(RegisterDto registerDto) {
        //1.拷贝数据到pojo
        User user = new User();
        BeanUtils.copyProperties(registerDto,user);
        //2.校验手机号码是否注册
//        LambdaQueryWrapper<User> usernameLambdaQueryWrapper=new LambdaQueryWrapper<>();
//        user = userMapper.selectOne(usernameLambdaQueryWrapper.eq(User::getPhone, user.getPhone()));
        if (userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getPhone,user.getPhone()))!=null){
            log.info("手机号码已注册");
            throw new BizException(ResultCode.PHONE_EXIST);

        }
        //3.校验用户名是否注册
        if (userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername,user.getUsername()))!=null){
            log.info("用户名已注册");
            throw new BizException(ResultCode.USER_EXIST);
        }
        //5.获取服务器存储的验证码
        String code = (String) redisTemplate.boundValueOps(SmsKey.REGISTER_SMS+user.getPhone()).get();
        if (StringUtils.isEmpty(code)){
            log.error("验证码失效...{}",user.getPhone());
            throw new BizException(ResultCode.LOGIN_SMS_EXPIRE);
        }
        //6.对比验证码是否正确
        if (!code.equals(registerDto.getCode())){
            log.error("验证码输入错误，手机号码:{},验证码:{}",user.getPhone(),registerDto.getCode());
            throw new BizException(ResultCode.REGISTER_CODE_ERROR);
        }
        //7.生成盐
        String salt = Md5Utils.createSalt();
        //8.密码加密
        String md5Password = Md5Utils.md5Password(user.getPassword(), salt);

        user.setPassword(md5Password);
        user.setSalt(salt);
        this.save(user);

    }

    @Override
    public TokenDto login(String phone, String code) {
        //1.获取服务器存储的验证码
        String serverCode= (String) redisTemplate.boundValueOps(SmsKey.LOGIN_SMS +phone).get();

        if(StringUtils.isEmpty(serverCode)){
            //验证码失效
            throw  new BizException(ResultCode.LOGIN_SMS_EXPIRE);
        }
        if(!code.equals(serverCode)){
            //验证码输入错误
            throw  new BizException(ResultCode.LOGIN_SMS_ERROR);
        }
        //根据手机号码查找账户
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getPhone, phone));
        if (user==null){
            log.info("手机号码未被注册");
            throw new BizException(ResultCode.USER_NOT_EXIST);
        }

        TokenDto tokenDto = handleLogin(user);

        return tokenDto;
    }

    @Override
    public User queryUserByToken(String token) {
        return null;
    }

    @Override
    public User queryUserByToPhone(String phone) {
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getPhone, phone));
        return user;
    }

    @Override
    public IPage<User> list(Page<User> page, String nickname) {
        return null;
    }




    private TokenDto handleLogin(User user) {

        TokenDto tokenDto=new TokenDto();

        if (user.getLoginType()==3) {
            log.info("移动端...");
            if (!StringUtils.isEmpty(user.getAppToken())) {
                log.info("处理app端重复登录...token:{}", user.getAppToken());
                redisTemplate.delete(SmsKey.LOGIN_TOKEN + user.getAppToken());
            }
        } else {
            log.info("pc端...");
            //处理重复登录
            if (!StringUtils.isEmpty(user.getPcToken())) {
                log.info("处理pc端重复登录...token:{}", user.getPcToken());
                redisTemplate.delete(SmsKey.LOGIN_TOKEN + user.getPcToken());
            }
        }


        //4.生成token
        String token = UUID.randomUUID().toString().replace("-", "");

        //5.存储用户信息到redis
        redisTemplate.boundValueOps(SmsKey.LOGIN_TOKEN + token).set(user);

        log.info("登录的token为:{}", token);

        //6.设置失效时间
        redisTemplate.boundValueOps(SmsKey.LOGIN_TOKEN + token).expire(SmsKey.LOGIN_EXPIRE, TimeUnit.SECONDS);

        //设置token
        tokenDto.setToken(token);

        //如果是手机app端，生成一个新的刷新token
        if(user.getLoginType()==3){

            log.info("app端处理长时间登录问题...");

            //生成刷新token
            String refreshToken = UUID.randomUUID().toString().replace("-", "");

            //设置刷新token
            user.setRefreshToken(SmsKey.REFRESH_TOKEN+refreshToken);

            //设置失效时间
            Calendar endTime = Calendar.getInstance();
            endTime.add(Calendar.DAY_OF_MONTH, 90);
            user.setRefreshTokenExpire(endTime.getTime());

            //设置刷新token到dto中
            tokenDto.setRefreshToken(refreshToken);
        }


        //7.设置登录的时间和IP地址
        user.setLastLoginTime(new Date());
//        user.setIpAddress(request.getRemoteAddr());

        if (user.getLoginType()==3) {
            user.setAppToken(token);
        } else {
            user.setPcToken(token);
        }

        //有id就是修改
      userMapper.insert(user);
        return tokenDto;
    }
}
